
#include <stdlib.h>
#include <stdarg.h>

#include "driver.h"

#include "fifo2.h"

#define LOG_UART_DEV		UART1
#define LOG_UART_TX_PIN		UART1_TX_PE0
#define LOG_UART_RX_PIN		UART1_RX_PE2

#define LOG_UART_BAUD		(2UL*1000UL*1000UL)

#define LOG_UART_DISABLE_IRQ_SAVE()	core_interrupt_disable()
#define LOG_UART_RESTORE_IRQ(_csr)	core_restore_interrupt(_csr)

#define PCLK_HZ		(sys_clk.pclk*1000UL*1000UL)

static uint8_t log_uart_buf[2048];

static fifo_t log_uart_fifo = {
	.size = sizeof(log_uart_buf),
	.buffer = log_uart_buf,
};

void log_uart_init(void){
	unsigned short div=0;
	unsigned char bwpc=0;

	uart_reset(LOG_UART_DEV);
	uart_set_pin(LOG_UART_TX_PIN, LOG_UART_RX_PIN);
	uart_cal_div_and_bwpc(LOG_UART_BAUD, PCLK_HZ, &div, &bwpc);
	uart_init(LOG_UART_DEV, div, bwpc, UART_PARITY_NONE, UART_STOP_BIT_ONE);
}

int log_uart_write(const void* data, unsigned int length){
	unsigned int csr = LOG_UART_DISABLE_IRQ_SAVE();
	uint32_t wlen = fifo_put_block(&log_uart_fifo, data, length);
	LOG_UART_RESTORE_IRQ(csr);
	return wlen;
}

int log_uart_put(char ch){
	unsigned int csr = LOG_UART_DISABLE_IRQ_SAVE();
	uint32_t wlen = fifo_put(&log_uart_fifo, (uint8_t*)&ch);
	LOG_UART_RESTORE_IRQ(csr);
	return wlen;
}


void log_uart_send(const void* data, size_t length){
	const uint8_t* p = data;
	const uint8_t* pend = p + length;
	
	while(p < pend){
		uart_send_byte(LOG_UART_DEV, *p);
		p++;
	}
}


void log_uart_service(void){
	unsigned int data_len;
	while((data_len = fifo_data_length(&log_uart_fifo)) != 0){
		uint8_t buf[64];
		if(data_len > sizeof(buf)){
			data_len = sizeof(buf);
		}
		unsigned int csr = LOG_UART_DISABLE_IRQ_SAVE();
		uint32_t rlen = fifo_get_block(&log_uart_fifo, buf, data_len);
		LOG_UART_RESTORE_IRQ(csr);
		log_uart_send(buf, rlen);
	}	
}

